﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Heritage.Codebox;

namespace Heritage.Models
{
    public class CityModel
    {
        public string GameName {get; set;}
        public int StartCondition {get; set;}
        public int MinPlayers { get; set; }
        public int MaxPlayers { get; set; }
        public int Mafia { get; set; }
        public int Komissar { get; set; }
        public int Sheriff { get; set; }
        public int Reanimator { get; set; }
        public int Maniac { get; set; }
        public int Girl { get; set; }
        public int Thief { get; set; }
        public int Private { get; set; }
        public int PublicVote { get; set; }
        public GameSchedule Schedule {get; set;}
        public int Advocat { get; set; }
        public double RatingForEnter { get; set;}
        public string GameDescription { get; set;}
        public string GameConditions { get; set; }
        public string StartConditionDescription { get; set; }
        public string ErrorText { get; set; }
        public bool ModeCreate { get; set; }
    }
    public class GameSchedule
    {
        public int StartHour { get; set; }
        public int FirstDayInMinutes { get; set; }
        public bool SnapТоNextHour { get; set; }
        public int TurnStepInMinutes { get; set; }
        public int StartTurnIntervalHour { get; set; }
        public int EndTurnIntervalHour { get; set; }
        public string GameDays { get; set; }
        public DateTime NextTurn { get; set; } 

        public void CalculateNextTurnTime(bool dayZero)
        {
            DateTime cur = DateTime.Now;
            cur = cur.AddSeconds(-cur.Second);
            if (dayZero)
            {
                cur = cur.AddMinutes(FirstDayInMinutes);
                if (SnapТоNextHour)
                {
                    if (cur.Minute > 0)
                    {
                        cur = cur.AddMinutes(-cur.Minute);
                        cur = cur.AddHours(1);
                    }
                }
            }
            else
            {
                cur = cur.AddMinutes(TurnStepInMinutes);
            }
            if (Utils.InsideBannedInterval(cur))
            {
                cur = Utils.GetBannedIntervalEnd(cur);
            }
            if (cur.Hour > EndTurnIntervalHour)
            {
                cur = new DateTime(cur.Year, cur.Month, cur.Day, 0, 0, 0).AddDays(1);
            }
            while (!ContainsDayOfWeek(cur.DayOfWeek, GameDays))
            {
                cur = new DateTime(cur.Year, cur.Month, cur.Day, 0, 0, 0).AddDays(1);
            }
            if (cur.Hour < StartTurnIntervalHour)
            {
                cur = new DateTime(cur.Year, cur.Month, cur.Day, StartTurnIntervalHour, 0, 0);
            }
            NextTurn = cur;
        }

        public void ProlongNextTurnTime(bool dayZero)
        {
            DateTime cur = NextTurn;
            if (Utils.InsideBannedInterval(cur))
            {
                cur = Utils.GetBannedIntervalEnd(cur);
            }
            if (cur.Hour > EndTurnIntervalHour)
            {
                cur = new DateTime(cur.Year, cur.Month, cur.Day, 0, 0, 0).AddDays(1);
            }
            while (!ContainsDayOfWeek(cur.DayOfWeek, GameDays))
            {
                cur = new DateTime(cur.Year, cur.Month, cur.Day, 0, 0, 0).AddDays(1);
            }
            if (cur.Hour < StartTurnIntervalHour)
            {
                cur = new DateTime(cur.Year, cur.Month, cur.Day, StartTurnIntervalHour, 0, 0);
            }
            NextTurn = cur;
        }

        private bool ContainsDayOfWeek(DayOfWeek dayOfWeek, string gameDays)
        {
            if (dayOfWeek == DayOfWeek.Monday && gameDays.Contains("A")) return true;
            if (dayOfWeek == DayOfWeek.Tuesday && gameDays.Contains("B")) return true;
            if (dayOfWeek == DayOfWeek.Wednesday && gameDays.Contains("C")) return true;
            if (dayOfWeek == DayOfWeek.Thursday && gameDays.Contains("D")) return true;
            if (dayOfWeek == DayOfWeek.Friday && gameDays.Contains("E")) return true;
            if (dayOfWeek == DayOfWeek.Saturday && gameDays.Contains("F")) return true;
            if (dayOfWeek == DayOfWeek.Sunday && gameDays.Contains("G")) return true;
            return false;
        }

        public string ToGameString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(string.Format("{0},{1},{2},{3},{4},{5},{6},{7}", StartHour, FirstDayInMinutes, SnapТоNextHour,
                      TurnStepInMinutes, StartTurnIntervalHour, EndTurnIntervalHour, GameDays, NextTurn.ToString("dd.MM.yyyy HH:mm:ss")));
            return sb.ToString();
        }
        public static GameSchedule FromGameString(string s)
        {
            try
            {
                GameSchedule gs = new GameSchedule();
                string[] all = s.Split(new[] {","}, StringSplitOptions.None);

                gs.StartHour = int.Parse(all[0]);
                gs.FirstDayInMinutes = int.Parse(all[1]);
                gs.SnapТоNextHour = bool.Parse(all[2]);
                gs.TurnStepInMinutes = int.Parse(all[3]);
                gs.StartTurnIntervalHour = int.Parse(all[4]);
                gs.EndTurnIntervalHour = int.Parse(all[5]);
                gs.GameDays = all[6];
                DateTime res = DateTime.MinValue;
                if (DateTime.TryParse(all[7], out res))
                {
                    gs.NextTurn = res;
                }

                return gs;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public string Description(bool html)
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("старт ");
                if (StartHour == -2) sb.Append("по заполнению\n");
                else if (StartHour == -1) sb.Append("производится мэром\n");
                else sb.Append(string.Format("в {0}:00\n", StartHour));
                TimeSpan ts = TimeSpan.FromMinutes(FirstDayInMinutes);
                sb.Append("длительность нуль-хода: ");
                if (ts.Days > 0) sb.Append(string.Format("{2} {0}{1}", DayString(ts.Days), ((ts.Hours > 0 || ts.Minutes > 0)?" ":""), ts.Days));
                if (ts.Hours > 0) sb.Append(string.Format("{2} {0}{1}", HourString(ts.Hours), (ts.Minutes > 0)?" ":"", ts.Hours));
                if (ts.Minutes > 0) sb.Append(string.Format("{1} {0}", MinuteString(ts.Minutes), ts.Minutes));
                sb.Append("\n");
                sb.Append("интервал между ходами: ");
                ts = TimeSpan.FromMinutes(TurnStepInMinutes);
                if (ts.Days > 0) sb.Append(string.Format("{2} {0}{1}", DayString(ts.Days), ((ts.Hours > 0 || ts.Minutes > 0) ? " " : ""), ts.Days));
                if (ts.Hours > 0) sb.Append(string.Format("{2} {0}{1}", HourString(ts.Hours), (ts.Minutes > 0) ? " " : "", ts.Hours));
                if (ts.Minutes > 0) sb.Append(string.Format("{1} {0}", MinuteString(ts.Minutes), ts.Minutes));
                sb.Append("\n");
                if (StartTurnIntervalHour == 0 && EndTurnIntervalHour == 23)
                {
                    sb.Append("игровое время: круглосуточно\n");
                }
                else
                {
                    sb.Append(string.Format("игровое время: {0}:00 - {1}:59\n", StartTurnIntervalHour,
                                            EndTurnIntervalHour));
                }
                if (GameDays != null) sb.Append(string.Format("игровые дни: {0}", GameDaysString(GameDays)));
                if (html) return sb.ToString().Replace("\n", "<br>");
                return sb.ToString();
            }
            catch (Exception ex)
            {
                return "какой-то косяк с описанием тут случился";
            }
        }

        private string GameDaysString(string gameDays)
        {
            string res = "";
            if (gameDays.IndexOf("A") >= 0) res += "пн, ";
            if (gameDays.IndexOf("B") >= 0) res += "вт, ";
            if (gameDays.IndexOf("C") >= 0) res += "ср, ";
            if (gameDays.IndexOf("D") >= 0) res += "чт, ";
            if (gameDays.IndexOf("E") >= 0) res += "пт, ";
            if (gameDays.IndexOf("F") >= 0) res += "сб, ";
            if (gameDays.IndexOf("G") >= 0) res += "вс, ";
            res = res.Substring(0, res.Length - 2);
            return res;
        }

        private string MinuteString(int minutes)
        {
            return TimeString(minutes, "минута", "минуты", "минут");
        }

        private string HourString(int hours)
        {
            return TimeString(hours, "час", "часа", "часов");
        }

        private string DayString(int days)
        {
            return TimeString(days, "день", "дня", "дней");
        }

        private string TimeString(int days, string one, string two, string ten)
        {
            if (days >= 5 && days <= 20) return ten;
            if (days % 10 == 0 || days % 10 > 4) return ten;
            if (days % 10 == 1) return one;
            return two;
        }

        public string NextTurnString()
        {
            StringBuilder sb = new StringBuilder();
            DateTime now = DateTime.Now;
            sb.Append("следующий ход будет ");
            if (NextTurn.Day == now.Day) sb.Append("сегодня ");
            else if (NextTurn.Day == now.AddDays(1).Day) sb.Append("завтра ");
            else if (NextTurn.Day == now.AddDays(2).Day) sb.Append("послезавтра ");
            else
            {
                sb.Append(string.Format("{0} {1} ", NextTurn.Day, GetMonthString(NextTurn.Month)));
            }
            sb.Append(string.Format(" в {0}:{1}", NextTurn.Hour<10?"0"+NextTurn.Hour: ""+NextTurn.Hour,  NextTurn.Minute<10?"0"+NextTurn.Minute: ""+NextTurn.Minute));
            return sb.ToString();
        }

        private string GetMonthString(int month)
        {
            if (month == 1) return "января";
            if (month == 2) return "февраля";
            if (month == 3) return "марта";
            if (month == 4) return "апреля";
            if (month == 5) return "мая";
            if (month == 6) return "июня";
            if (month == 7) return "июля";
            if (month == 8) return "августа";
            if (month == 9) return "сентября";
            if (month == 10) return "октября";
            if (month == 11) return "ноября";
            if (month == 12) return "декабря";
            return "";
        }
    }
}